<script setup>
import { ref, onMounted, onUnmounted, nextTick, computed, watch } from 'vue'
import LoginRegister from './components/LoginRegister.vue'
import FriendList from './components/FriendList.vue'
import FriendManager from './components/FriendManager.vue'

// 用户登录状态
const user = ref(null)
const friends = ref([]) // 好友列表
const currentChat = ref(null) // 当前聊天对象，null为群聊，字符串为私聊用户名
const currentPage = ref('message') // 'home', 'message', 'friends', 'more'

// 会话列表
const conversations = ref([]) // [{friend, avatar, lastMsg, lastTime, unread}]

// 响应式数据
const messages = ref([])
const privateMessages = ref({}) // { userId: [msg, ...] }
const onlineUsers = ref([])
const typingUsers = ref([])
const messageText = ref('')
const currentUserId = ref(null)
const connectionStatus = ref('connecting')
const statusText = ref('连接中...')
const showModal = ref(false)
const modalImageSrc = ref('')
const chatMessages = ref(null)
const showEmojiPicker = ref(false)
const showFriendManager = ref(false)
const showAddFriend = ref(false)
const addFriendName = ref('')
const addFriendError = ref('')

// 表情符号列表
const emojis = [
  '😊', '😂', '🤣', '❤️', '😍', '😒', '😭', '😡', '😱', '😎',
  '👍', '👎', '👏', '🙏', '🎉', '🎊', '🎈', '🎁', '💯', '🔥',
  '😀', '😃', '😄', '😁', '😆', '😅', '🤗', '🤔', '🤨', '😐',
  '😑', '😶', '🙄', '😏', '😣', '😥', '😮', '🤐', '😯', '😪',
  '😴', '😌', '😛', '😜', '😝', '🤤', '😒', '😓', '😔', '😕',
  '🙃', '🤑', '😲', '☹️', '🙁', '😖', '😞', '😟', '😤', '😢',
  '😭', '😦', '😧', '😨', '😩', '🤯', '😬', '😰', '😱', '🥵',
  '🥶', '😳', '🤪', '🤨', '🧐', '🤓', '😈', '👿', '👹', '👺',
  '💀', '👻', '👽', '🤖', '💩', '😺', '😸', '😹', '😻', '😼',
  '😽', '🙀', '😿', '😾', '🙈', '🙉', '🙊', '👶', '👧', '🧒'
]

// 响应式窗口大小
const windowWidth = ref(window.innerWidth)

// 响应式用户显示计算属性
const visibleUsers = computed(() => {
  let maxVisible = 5 // 默认显示5个用户
  
  if (windowWidth.value < 768) { // 手机端
    maxVisible = 3
  } else if (windowWidth.value < 1024) { // 平板
    maxVisible = 4
  } else { // 桌面端
    maxVisible = 6
  }
  
  return onlineUsers.value.slice(0, maxVisible)
})

const hiddenUsersCount = computed(() => {
  return Math.max(0, onlineUsers.value.length - visibleUsers.value.length)
})

// WebSocket连接
let ws = null
let reconnectTimer = null
let typingTimer = null

// 连接WebSocket
const connectWebSocket = () => {
  try {
    ws = new WebSocket('ws://localhost:3000/ws')
    
    ws.onopen = () => {
      if (user.value?.id) {
        ws.send(JSON.stringify({ type: 'bind', data: { user_id: user.value.id } }))
      }
      connectionStatus.value = 'connected'
      statusText.value = '已连接'
      console.log('WebSocket连接已建立')
    }
    
    ws.onmessage = (event) => {
      const data = JSON.parse(event.data)
      handleWebSocketMessage(data)
    }
    
    ws.onclose = () => {
      connectionStatus.value = 'disconnected'
      statusText.value = '连接断开'
      console.log('WebSocket连接已关闭')
      scheduleReconnect()
    }
    
    ws.onerror = (error) => {
      console.error('WebSocket错误:', error)
      connectionStatus.value = 'disconnected'
      statusText.value = '连接错误'
    }
  } catch (error) {
    console.error('连接WebSocket失败:', error)
  }
}

// 处理WebSocket消息（增加私聊消息处理）
const handleWebSocketMessage = (data) => {
  switch (data.type) {
    case 'welcome':
      currentUserId.value = data.data.userId
      addMessage({
        id: Date.now(),
        type: 'system',
        text: data.data.message,
        timestamp: new Date()
      })
      break
    case 'chat':
      addMessage({
        id: Date.now(),
        type: 'text',
        text: data.data.text,
        username: data.data.username,
        userId: data.data.userId,
        avatar_color: data.data.avatar_color,
        avatar_text: data.data.avatar_text,
        messageId: data.data.messageId,
        timestamp: new Date(data.data.timestamp)
      })
      break
    case 'private_chat':
      // 私聊消息
      const fromId = data.data.from
      const toId = data.data.to
      const msg = {
        id: Date.now(),
        type: 'private',
        text: data.data.text,
        from: fromId,
        to: toId,
        avatar_color: data.data.avatar_color,
        avatar_text: data.data.avatar_text,
        timestamp: new Date(data.data.timestamp)
      }
      const friendId = fromId === user.value?.id ? toId : fromId
      if (!privateMessages.value[friendId]) privateMessages.value[friendId] = []
      privateMessages.value[friendId].push(msg)
      // 更新会话列表
      updateConversation(friendId, data.data.text, fromId === user.value?.id)
      break
    case 'image':
      addMessage({
        id: Date.now(),
        type: 'image',
        imageData: data.data.imageData,
        fileName: data.data.fileName,
        username: data.data.username,
        userId: data.data.userId,
        avatar_color: data.data.avatar_color,
        avatar_text: data.data.avatar_text,
        messageId: data.data.messageId,
        timestamp: new Date(data.data.timestamp)
      })
      break
    case 'userList':
      onlineUsers.value = data.data
      break
    case 'userJoined':
      addMessage({
        id: Date.now(),
        type: 'system',
        text: data.data.message,
        timestamp: new Date(data.data.timestamp)
      })
      break
    case 'userLeft':
      addMessage({
        id: Date.now(),
        type: 'system',
        text: data.data.message,
        timestamp: new Date(data.data.timestamp)
      })
      break
    case 'typing':
      handleTypingUpdate(data.data)
      break
  }
}

// 添加消息
const addMessage = (message) => {
  messages.value.push(message)
  scrollToBottom()
}



// 滚动到底部
const scrollToBottom = async () => {
  await nextTick()
  if (chatMessages.value) {
    chatMessages.value.scrollTop = chatMessages.value.scrollHeight
  }
}

// 发送消息（区分群聊/私聊）
const sendMessage = () => {
  if (!messageText.value.trim() || !ws || ws.readyState !== WebSocket.OPEN) return
  if (currentChat.value) {
    // 私聊
    ws.send(JSON.stringify({
      type: 'private_chat',
      data: {
        to: currentChat.value,
        text: messageText.value.trim()
      }
    }))
    // 本地也加入一条
    if (!privateMessages.value[currentChat.value]) privateMessages.value[currentChat.value] = []
    privateMessages.value[currentChat.value].push({
      id: Date.now(),
      type: 'private',
      text: messageText.value.trim(),
      from: user.value?.id,
      to: currentChat.value,
      avatar_color: user.value?.avatar_color,
      avatar_text: user.value?.avatar_text,
      timestamp: new Date()
    })
    // 更新会话列表
    updateConversation(currentChat.value, messageText.value.trim(), true)
  } else {
    // 群聊
    ws.send(JSON.stringify({
      type: 'chat',
      data: { text: messageText.value.trim() }
    }))
  }
  messageText.value = ''
  stopTyping()
  showEmojiPicker.value = false
}

// 处理图片上传
const handleImageUpload = (event) => {
  const file = event.target.files[0]
  if (!file) return
  
  if (file.size > 5 * 1024 * 1024) {
    alert('图片大小不能超过5MB')
    return
  }
  
  const reader = new FileReader()
  reader.onload = (e) => {
    const imageData = e.target.result
    const imageId = Date.now().toString()
    
    ws.send(JSON.stringify({
      type: 'image',
      data: {
        imageId: imageId,
        fileName: file.name,
        imageData: imageData,
        size: file.size
      }
    }))
  }
  reader.readAsDataURL(file)
  
  // 清空input
  event.target.value = ''
}

// 处理打字状态
const handleTyping = () => {
  if (!ws || ws.readyState !== WebSocket.OPEN) return
  
  ws.send(JSON.stringify({
    type: 'typing',
    data: { isTyping: true }
  }))
  
  // 清除之前的定时器
  if (typingTimer) {
    clearTimeout(typingTimer)
  }
  
  // 3秒后停止打字状态
  typingTimer = setTimeout(() => {
    stopTyping()
  }, 3000)
}

// 停止打字状态
const stopTyping = () => {
  if (!ws || ws.readyState !== WebSocket.OPEN) return
  
  ws.send(JSON.stringify({
    type: 'typing',
    data: { isTyping: false }
  }))
}

// 处理打字状态更新
const handleTypingUpdate = (data) => {
  if (data.isTyping) {
    if (!typingUsers.value.includes(data.username)) {
      typingUsers.value.push(data.username)
    }
  } else {
    typingUsers.value = typingUsers.value.filter(user => user !== data.username)
  }
}

// 显示图片模态框
const showImageModal = (imageSrc) => {
  modalImageSrc.value = imageSrc
  showModal.value = true
}

// 隐藏图片模态框
const hideImageModal = () => {
  showModal.value = false
  modalImageSrc.value = ''
}

// 处理图片加载错误
const handleImageError = (event) => {
  event.target.style.display = 'none'
  event.target.nextSibling.textContent = '图片加载失败'
}

// 切换表情符号选择器
const toggleEmojiPicker = () => {
  showEmojiPicker.value = !showEmojiPicker.value
}

// 插入表情符号
const insertEmoji = (emoji) => {
  messageText.value += emoji
  showEmojiPicker.value = false
}

// 格式化文本（支持表情符号）
const formatText = (text) => {
  return text.replace(/\n/g, '<br>')
}

// 获取消息样式类
const getMessageClass = (message) => {
  if (message.type === 'system') return 'system'
  if (message.type === 'private') return 'private'
  return message.userId === currentUserId.value ? 'sent' : 'received'
}

// 格式化时间
const formatTime = (timestamp) => {
  const date = new Date(timestamp)
  return date.toLocaleTimeString('zh-CN', { 
    hour: '2-digit', 
    minute: '2-digit' 
  })
}

// 辅助函数：格式化时间
function formatTimeShort(date) {
  const d = new Date(date)
  return d.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
}

// 更新会话列表
function updateConversation(friendId, msg, isSelf = false) {
  let conv = conversations.value.find(c => c.friendId === friendId)
  const now = new Date()
  if (!conv) {
    conv = {
      friendId,
      avatar: friendId[0].toUpperCase(),
      lastMsg: msg,
      lastTime: now,
      unread: isSelf ? 0 : 1
    }
    conversations.value.unshift(conv)
  } else {
    conv.lastMsg = msg
    conv.lastTime = now
    if (!isSelf) conv.unread = (conv.unread || 0) + 1
    // 移到最前
    conversations.value = [conv, ...conversations.value.filter(c => c.friendId !== friendId)]
  }
}

// 进入会话时清除未读
function enterConversation(friendId) {
  const conv = conversations.value.find(c => c.friendId === friendId)
  if (conv) conv.unread = 0
  currentChat.value = friendId
  currentPage.value = 'message'
}

// 安排重连
const scheduleReconnect = () => {
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
  }
  reconnectTimer = setTimeout(() => {
    console.log('尝试重新连接...')
    connectWebSocket()
  }, 3000)
}

// 点击外部关闭表情符号选择器
const handleClickOutside = (event) => {
  if (showEmojiPicker.value && !event.target.closest('.emoji-picker')) {
    showEmojiPicker.value = false
  }
}

// 处理窗口大小变化
const handleResize = () => {
  windowWidth.value = window.innerWidth
}

// 登录状态持久化
onMounted(() => {
  const savedUser = localStorage.getItem('im_user')
  if (savedUser) {
    try {
      const parsed = JSON.parse(savedUser)
      user.value = parsed
      friends.value = Array.from(parsed.friends || [])
    } catch {}
  }
  connectWebSocket()
  document.addEventListener('click', handleClickOutside)
  window.addEventListener('resize', handleResize)
})

// 组件卸载时清理
onUnmounted(() => {
  if (ws) {
    ws.close()
  }
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
  }
  if (typingTimer) {
    clearTimeout(typingTimer)
  }
  document.removeEventListener('click', handleClickOutside)
  window.removeEventListener('resize', handleResize)
})

// 登录成功回调
const handleLoginSuccess = (userInfo) => {
  user.value = userInfo
  // 初始化好友列表
  friends.value = Array.from(userInfo.friends || [])
  // 可在此处初始化WebSocket连接，或刷新页面数据
  localStorage.setItem('im_user', JSON.stringify(userInfo))
}

// 好友添加/删除后刷新
const handleFriendAdded = (name) => {
  if (!friends.value.includes(name)) friends.value.push(name)
}
const handleFriendRemoved = (name) => {
  friends.value = friends.value.filter(f => f !== name)
  // 如果正在和该好友私聊，自动切回群聊
  if (currentChat.value === name) currentChat.value = null
}

// 切换私聊窗口
const handleSelectFriend = (name) => {
  currentChat.value = name
}
const handleBackToGroup = () => {
  currentChat.value = null
}

// 聊天消息列表（根据当前聊天对象切换）
const chatList = computed(() => {
  if (currentChat.value) {
    return privateMessages.value[currentChat.value] || []
  } else {
    return messages.value
  }
})

const handleLogout = () => {
  user.value = null
  friends.value = []
  currentChat.value = null
  currentPage.value = 'message'
  localStorage.removeItem('im_user')
}

// 消息Tab渲染会话卡片
const sortedConversations = computed(() => {
  return (conversations.value || []).slice().sort((a, b) => new Date(b.lastTime) - new Date(a.lastTime))
})

// 生成彩色圆背景
function getAvatarColor(name) {
  const colors = ['#90caf9', '#f48fb1', '#b2dfdb', '#ffe082', '#a5d6a7', '#ce93d8', '#ffab91']
  let hash = 0
  for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash)
  return colors[Math.abs(hash) % colors.length]
}

// 好友列表卡片数据
const friendCards = computed(() => {
  return (friends.value || []).map(friend => {
    // 查找最近一条消息
    let lastMsg = ''
    let lastTime = ''
    let unread = 0
    if (privateMessages.value[friend.id]) { // 使用userId作为key
      const msgs = privateMessages.value[friend.id]
      const last = msgs[msgs.length - 1]
      lastMsg = last.text
      lastTime = formatTimeShort(last.timestamp)
      // 统计未读
      const conv = conversations.value.find(c => c.friendId === friend.id)
      unread = conv ? conv.unread : 0
    }
    return {
      friendId: friend.id,
      friendName: friend.username,
      avatar: friend.username[0].toUpperCase(),
      color: getAvatarColor(friend.username),
      lastMsg,
      lastTime,
      unread
    }
  })
})

function openAddFriend() {
  addFriendName.value = ''
  addFriendError.value = ''
  showAddFriend.value = true
}
function closeAddFriend() {
  showAddFriend.value = false
}
async function handleAddFriendSubmit() {
  addFriendError.value = ''
  const name = addFriendName.value.trim()
  if (!name) {
    addFriendError.value = '请输入好友用户名'
    return
  }
  if (name === user.value?.username) {
    addFriendError.value = '不能添加自己为好友'
    return
  }
  try {
    const res = await fetch('http://localhost:3000/add_friend', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username: user.value?.username, friend: name })
    })
    const data = await res.json()
    if (!data.success) {
      addFriendError.value = data.msg || '添加失败'
      return
    }
    handleFriendAdded(name)
    showAddFriend.value = false
  } catch (e) {
    addFriendError.value = '网络错误'
  }
}

const chatView = ref({ show: false, friendId: '', friendName: '', signature: '' })

// 假设好友签名数据（可后端扩展）
const friendSignatures = ref({}) // { userId: signature }

function enterFriendChat(friendId, friendName) {
  chatView.value = {
    show: true,
    friendId,
    friendName,
    signature: friendSignatures.value?.[friendId] || '对方很个性，暂无签名'
  }
  enterConversation(friendId)
}
function closeChatView() {
  chatView.value = { show: false, friendId: '', friendName: '', signature: '' }
}

function sendMessageToChat() {
  if (!messageText.value.trim() || !ws || ws.readyState !== WebSocket.OPEN || !chatView.value.friendId || !user.value) return;
  // 本地立即push
  if (!privateMessages.value[chatView.value.friendId]) privateMessages.value[chatView.value.friendId] = [];
  privateMessages.value[chatView.value.friendId].push({
    id: Date.now(),
    type: 'private',
    text: messageText.value.trim(),
    from: user.value.id,
    to: chatView.value.friendId,
    avatar_color: user.value.avatar_color,
    avatar_text: user.value.avatar_text,
    timestamp: new Date()
  });
  // 发送到后端，to字段用userId
  ws.send(JSON.stringify({
    type: 'private_chat',
    data: {
      to: chatView.value.friendId,
      text: messageText.value.trim()
    }
  }));
  updateConversation(chatView.value.friendId, messageText.value.trim(), true);
  messageText.value = '';
  stopTyping();
  showEmojiPicker.value = false;
}
</script>

<template>
  <div class="app-bg">
    <LoginRegister v-if="!user" @login-success="handleLoginSuccess" />
    <div v-else class="main-mobile-container">
      <!-- 顶部渐变+大标题 -->
      <div class="top-gradient">
        <div class="top-bar">
          <span class="top-title">
            <template v-if="currentPage === 'home'">首页</template>
            <template v-else-if="currentPage === 'message'">消息</template>
            <template v-else-if="currentPage === 'friends'">好友</template>
            <template v-else>更多</template>
          </span>
          <span class="user-info">{{ user?.username }}</span>
          <button class="logout-btn" @click="handleLogout">退出</button>
        </div>
        <div v-if="currentPage === 'message' || currentPage === 'friends'" class="search-bar">
          <input type="text" placeholder="搜索" />
        </div>
      </div>
      <!-- 主内容区 -->
      <div class="main-content">
        <div v-if="currentPage === 'home'" class="tab-page home-page">
          <div class="empty-tip">首页内容自定义</div>
        </div>
        <div v-else-if="currentPage === 'message'" class="tab-page message-page">
          <div class="msg-card-list">
            <div v-for="conv in sortedConversations" :key="conv.friendId" class="msg-card" @click="enterConversation(conv.friendId)">
              <div class="msg-avatar" :style="{background: '#b2dfdb'}"><span>{{ conv.avatar }}</span></div>
              <div class="msg-main">
                <div class="msg-title">{{ conv.friend }}</div>
                <div class="msg-desc">{{ conv.lastMsg }}</div>
              </div>
              <div class="msg-extra">
                <span v-if="conv.unread > 0" class="msg-badge">{{ conv.unread }}</span>
                <span class="msg-time">{{ formatTimeShort(conv.lastTime) }}</span>
              </div>
            </div>
            <div v-if="!sortedConversations.length" class="empty-tip">暂无会话</div>
          </div>
        </div>
        <div v-else-if="currentPage === 'friends'" class="tab-page friend-page">
          <div class="friend-list-cards">
            <div v-for="card in friendCards" :key="card.friendId" class="friend-card" @click="enterFriendChat(card.friendId, card.friendName)">
              <div class="friend-avatar" :style="{background: card.color}">{{ card.avatar }}</div>
              <div class="friend-main">
                <div class="friend-title">{{ card.friendName }}</div>
                <div class="friend-desc">{{ card.signature }}</div>
              </div>
              <div class="friend-extra">
                <span v-if="card.unread > 0" class="friend-badge">{{ card.unread }}</span>
                <span class="friend-time">{{ card.lastTime }}</span>
              </div>
            </div>
            <div v-if="!friendCards.length" class="empty-tip">暂无好友</div>
          </div>
          <!-- 右下角悬浮+号按钮 -->
          <button class="fab-add-friend" @click="openAddFriend">+</button>
          <!-- 添加好友弹出层 -->
          <div v-if="showAddFriend" class="add-friend-modal-mask" @click.self="closeAddFriend">
            <div class="add-friend-modal">
              <div class="add-friend-title">添加好友</div>
              <form @submit.prevent="handleAddFriendSubmit">
                <input v-model="addFriendName" type="text" placeholder="输入用户名" maxlength="20" />
                <button type="submit">添加</button>
              </form>
              <div v-if="addFriendError" class="add-friend-error">{{ addFriendError }}</div>
            </div>
          </div>
        </div>
        <div v-else class="tab-page more-page">
          <div class="empty-tip">更多功能自定义</div>
        </div>
      </div>
      <!-- 底部导航栏 -->
      <div class="bottom-nav">
        <button :class="{active: currentPage==='home'}" @click="currentPage='home'">
          <span class="nav-icon">🏠</span>
          <span>首页</span>
        </button>
        <button :class="{active: currentPage==='message'}" @click="currentPage='message'">
          <span class="nav-icon">💬</span>
          <span>消息</span>
        </button>
        <button :class="{active: currentPage==='friends'}" @click="currentPage='friends'">
          <span class="nav-icon">👥</span>
          <span>好友</span>
        </button>
        <button :class="{active: currentPage==='more'}" @click="currentPage='more'">
          <span class="nav-icon">☰</span>
          <span>更多</span>
        </button>
      </div>
    </div>
    <!-- 聊天页面 -->
    <div v-if="chatView.show && user" class="chat-view-page">
      <div class="chat-view-header">
        <button class="chat-back-btn" @click="closeChatView">←</button>
        <span class="chat-view-title">{{ chatView.friendName }}</span>
      </div>
      <div class="chat-view-signature">{{ chatView.signature }}</div>
      <div class="chat-view-messages">
        <div v-for="msg in (privateMessages[chatView.friendId] || [])" :key="msg.id" :class="['chat-bubble', msg.from === user?.id ? 'sent' : 'received']">
          <span class="bubble-content">{{ msg.text }}</span>
          <span class="bubble-time">{{ formatTimeShort(msg.timestamp) }}</span>
        </div>
      </div>
      <div class="chat-view-input">
        <input v-model="messageText" type="text" placeholder="输入消息..." maxlength="200" @keyup.enter="sendMessageToChat" />
        <button @click="sendMessageToChat" :disabled="!messageText.trim()">发送</button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.app-bg {
  min-height: 100vh;
  background: linear-gradient(135deg, #e8f5e9 0%, #b2dfdb 100%);
  width: 100vw;
  overflow-x: hidden;
}
.main-mobile-container {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
}
.top-gradient {
  width: 100%;
  padding-top: 18px;
  background: linear-gradient(135deg, #e8f5e9 0%, #b2dfdb 100%);
  border-bottom-left-radius: 24px;
  border-bottom-right-radius: 24px;
  box-shadow: 0 2px 12px rgba(76, 175, 80, 0.06);
}
.top-bar {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 18px 0 24px;
  height: 48px;
  gap: 12px;
}
.top-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: #43a047;
  letter-spacing: 1px;
  flex: 1 0 auto;
}
.user-info {
  color: #388e3c;
  font-weight: 500;
  font-size: 1.05rem;
  margin-left: auto;
  margin-right: 10px;
}
.logout-btn {
  background: linear-gradient(90deg, #e57373 0%, #f44336 100%);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 6px 18px;
  font-size: 1rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
}
.logout-btn:hover {
  background: linear-gradient(90deg, #c62828 0%, #e57373 100%);
}
.search-bar {
  width: 100%;
  display: flex;
  justify-content: center;
  margin: 12px 0 0 0;
}
.search-bar input {
  width: 90vw;
  max-width: 600px;
  padding: 12px 18px;
  border-radius: 24px;
  border: 1.5px solid #b2dfdb;
  background: #f1f8e9;
  font-size: 1.1rem;
  outline: none;
  transition: border-color 0.2s;
}
.search-bar input:focus {
  border-color: #43a047;
}
.main-content {
  flex: 1;
  width: 100vw;
  max-width: 900px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-bottom: 70px;
}
.tab-page {
  width: 100%;
  margin-top: 18px;
}
.empty-tip {
  color: #aaa;
  font-size: 1.1rem;
  text-align: center;
  margin-top: 40px;
}
/* 消息卡片列表 */
.msg-card-list {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.msg-card {
  display: flex;
  align-items: center;
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 2px 12px rgba(76, 175, 80, 0.06);
  padding: 18px 18px 14px 18px;
  gap: 16px;
  position: relative;
}
.msg-avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: #b2dfdb;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  color: #fff;
  flex-shrink: 0;
}
.msg-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.msg-title {
  font-size: 1.13rem;
  font-weight: 600;
  color: #222;
}
.msg-desc {
  font-size: 1rem;
  color: #888;
}
.msg-extra {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  min-width: 40px;
}
.msg-badge {
  background: #f44336;
  color: #fff;
  border-radius: 12px;
  padding: 2px 10px;
  font-size: 0.95rem;
  font-weight: 600;
  margin-bottom: 4px;
}
.msg-time {
  color: #888;
  font-size: 0.95rem;
  margin-top: 2px;
}
.bottom-nav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: 60px;
  background: #fff;
  border-top: 1.5px solid #b2dfdb;
  display: flex;
  justify-content: space-around;
  align-items: center;
  z-index: 100;
  box-shadow: 0 -2px 12px rgba(76, 175, 80, 0.06);
}
.bottom-nav button {
  background: none;
  border: none;
  outline: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-size: 1.05rem;
  color: #888;
  cursor: pointer;
  padding: 0 8px;
  transition: color 0.2s;
}
.bottom-nav button.active {
  color: #43a047;
  font-weight: 600;
}
.nav-icon {
  font-size: 1.5rem;
}
.friend-list-cards {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding-bottom: 80px;
}
.friend-card {
  display: flex;
  align-items: center;
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 2px 12px rgba(76, 175, 80, 0.06);
  padding: 16px 18px 14px 18px;
  gap: 16px;
  position: relative;
  cursor: pointer;
  transition: box-shadow 0.2s;
}
.friend-card:hover {
  box-shadow: 0 4px 18px rgba(76, 175, 80, 0.13);
}
.friend-avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: #b2dfdb;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  color: #fff;
  flex-shrink: 0;
  font-weight: 700;
}
.friend-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.friend-title {
  font-size: 1.13rem;
  font-weight: 600;
  color: #222;
}
.friend-desc {
  font-size: 1rem;
  color: #888;
}
.friend-extra {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  min-width: 40px;
}
.friend-badge {
  background: #1976d2;
  color: #fff;
  border-radius: 12px;
  padding: 2px 10px;
  font-size: 0.95rem;
  font-weight: 600;
  margin-bottom: 4px;
}
.friend-time {
  color: #888;
  font-size: 0.95rem;
  margin-top: 2px;
}
.fab-add-friend {
  position: fixed;
  right: 28px;
  bottom: 90px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: linear-gradient(135deg, #43a047 0%, #66bb6a 100%);
  color: #fff;
  font-size: 2.2rem;
  border: none;
  box-shadow: 0 4px 18px rgba(76, 175, 80, 0.18);
  cursor: pointer;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
}
.fab-add-friend:hover {
  background: linear-gradient(135deg, #388e3c 0%, #43a047 100%);
}
.add-friend-modal-mask {
  position: fixed;
  left: 0; top: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.18);
  z-index: 3000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.add-friend-modal {
  width: 100vw;
  max-width: 480px;
  background: #fff;
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -2px 18px rgba(76, 175, 80, 0.10);
  padding: 32px 24px 24px 24px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  margin-bottom: 0;
}
.add-friend-title {
  font-size: 1.3rem;
  font-weight: 600;
  color: #43a047;
  margin-bottom: 18px;
  text-align: center;
}
.add-friend-modal input {
  width: 100%;
  padding: 12px 16px;
  border-radius: 8px;
  border: 1.5px solid #b2dfdb;
  background: #f1f8e9;
  font-size: 1.1rem;
  outline: none;
  margin-bottom: 14px;
}
.add-friend-modal button {
  width: 100%;
  padding: 12px 0;
  background: linear-gradient(90deg, #43a047 0%, #66bb6a 100%);
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: 1.1rem;
  font-weight: 600;
  cursor: pointer;
  margin-bottom: 8px;
}
.add-friend-error {
  color: #f44336;
  font-size: 1rem;
  text-align: center;
  margin-top: 4px;
}
@media (max-width: 600px) {
  .main-content {
    max-width: 100vw;
    padding-bottom: 70px;
  }
  .friend-manager-main {
    max-width: 98vw;
    padding: 10px 2px 8px 2px;
  }
  .msg-card-list {
    max-width: 98vw;
  }
  .friend-list-cards {
    max-width: 98vw;
  }
  .add-friend-modal {
    max-width: 98vw;
    padding: 18px 6px 12px 6px;
  }
}
.chat-view-page {
  position: fixed;
  left: 0; top: 0; right: 0; bottom: 0;
  background: #fff;
  z-index: 4000;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
}
.chat-view-header {
  display: flex;
  align-items: center;
  height: 56px;
  background: linear-gradient(90deg, #e8f5e9 0%, #b2dfdb 100%);
  box-shadow: 0 2px 8px rgba(76, 175, 80, 0.06);
  padding: 0 18px;
}
.chat-back-btn {
  background: none;
  border: none;
  font-size: 1.5rem;
  color: #43a047;
  cursor: pointer;
  margin-right: 12px;
}
.chat-view-title {
  font-size: 1.2rem;
  font-weight: 700;
  color: #222;
}
.chat-view-signature {
  color: #888;
  font-size: 1rem;
  padding: 8px 18px 0 18px;
  border-bottom: 1px solid #e0f2f1;
  margin-bottom: 6px;
}
.chat-view-messages {
  flex: 1;
  overflow-y: auto;
  padding: 18px 12px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.chat-bubble {
  max-width: 70vw;
  padding: 10px 16px;
  border-radius: 18px;
  font-size: 1.08rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  box-shadow: 0 2px 8px rgba(76, 175, 80, 0.06);
  background: #f1f8e9;
  color: #222;
}
.chat-bubble.sent {
  align-self: flex-end;
  background: linear-gradient(90deg, #43a047 0%, #b2dfdb 100%);
  color: #fff;
}
.bubble-content {
  margin-bottom: 4px;
}
.bubble-time {
  font-size: 0.85rem;
  color: #888;
  align-self: flex-end;
}
.chat-view-input {
  display: flex;
  align-items: center;
  padding: 12px 10px;
  border-top: 1px solid #e0f2f1;
  background: #fff;
  gap: 8px;
}
.chat-view-input input {
  flex: 1;
  padding: 10px 14px;
  border-radius: 18px;
  border: 1.5px solid #b2dfdb;
  background: #f1f8e9;
  font-size: 1.08rem;
  outline: none;
}
.chat-view-input button {
  padding: 10px 22px;
  background: linear-gradient(90deg, #43a047 0%, #66bb6a 100%);
  color: #fff;
  border: none;
  border-radius: 18px;
  font-size: 1.08rem;
  font-weight: 600;
  cursor: pointer;
}
</style>
